package com.microservice.common.util;

import com.microservice.common.properties.MailProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 邮件工具类
 * 
 * 注意：所有 sendXxxAsync 方法都是异步的，不会阻塞主线程
 * 如果需要同步发送（等待发送结果），使用不带 Async 后缀的方法
 * 
 * 频率限制：使用 Redis 实现，同一发送人在1分钟内只能发送一次邮件给同一收件人
 */
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnBean(JavaMailSender.class)
public class MailUtil {
    
    private final JavaMailSender mailSender;
    private final MailProperties mailProperties;
    private final StringRedisTemplate redisTemplate;
    
    private static final String MAIL_FREQUENCY_KEY_PREFIX = "mail:frequency:";
    private static final long FREQUENCY_LIMIT_SECONDS = 60; // 1分钟频率限制
    
    // ==================== 同步发送方法（带发送人参数和频率限制） ====================
    
    /**
     * 发送简单文本邮件（同步，带频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendSimpleMailAsync 异步方法
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     * @return 是否成功
     */
    public boolean sendSimpleMail(String senderId, String to, String subject, String content) {
        return sendSimpleMail(senderId, new String[]{to}, subject, content);
    }
    
    /**
     * 发送简单文本邮件（同步，无频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendSimpleMailAsync 异步方法
     *
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     * @return 是否成功
     */
    public boolean sendSimpleMail(String to, String subject, String content) {
        return sendSimpleMail(null, new String[]{to}, subject, content);
    }
    
    /**
     * 发送简单文本邮件（批量，同步，带频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendSimpleMailAsync 异步方法
     *
     * @param senderId 发送人ID（用于频率限制，可为null表示不限制）
     * @param to 收件人列表
     * @param subject 主题
     * @param content 内容
     * @return 是否成功
     */
    public boolean sendSimpleMail(String senderId, String[] to, String subject, String content) {
        // 检查频率限制
        if (senderId != null && !checkFrequencyLimit(senderId, to[0])) {
            log.warn("邮件发送频率限制: senderId={}, to={}, 1分钟内已发送过", senderId, to[0]);
            return false;
        }
        
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(getFromAddress());
            message.setTo(to);
            message.setSubject(subject);
            message.setText(content);
            
            mailSender.send(message);
            log.info("发送简单邮件成功: senderId={}, to={}, subject={}", senderId, to, subject);
            
            // 记录发送频率
            if (senderId != null) {
                recordSendFrequency(senderId, to[0]);
            }
            return true;
        } catch (Exception e) {
            log.error("发送简单邮件失败: senderId={}, to={}, subject={}, error={}", senderId, to, subject, e.getMessage());
            return false;
        }
    }
    
    /**
     * 发送简单文本邮件（批量，同步，无频率限制）
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param content 内容
     * @return 是否成功
     */
    public boolean sendSimpleMail(String[] to, String subject, String content) {
        return sendSimpleMail(null, to, subject, content);
    }
    
    /**
     * 发送 HTML 邮件（同步，带频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendHtmlMailAsync 异步方法
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @return 是否成功
     */
    public boolean sendHtmlMail(String senderId, String to, String subject, String htmlContent) {
        return sendHtmlMail(senderId, new String[]{to}, subject, htmlContent, null);
    }
    
    /**
     * 发送 HTML 邮件（同步，无频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendHtmlMailAsync 异步方法
     *
     * @param to 收件人
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @return 是否成功
     */
    public boolean sendHtmlMail(String to, String subject, String htmlContent) {
        return sendHtmlMail(null, new String[]{to}, subject, htmlContent, null);
    }
    
    /**
     * 发送 HTML 邮件（带抄送，同步，带频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendHtmlMailAsync 异步方法
     *
     * @param senderId 发送人ID（用于频率限制，可为null表示不限制）
     * @param to 收件人列表
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param cc 抄送列表
     * @return 是否成功
     */
    public boolean sendHtmlMail(String senderId, String[] to, String subject, String htmlContent, String[] cc) {
        // 检查频率限制
        if (senderId != null && !checkFrequencyLimit(senderId, to[0])) {
            log.warn("邮件发送频率限制: senderId={}, to={}, 1分钟内已发送过", senderId, to[0]);
            return false;
        }
        
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, mailProperties.getDefaultEncoding());
            
            helper.setFrom(getFromAddress(), mailProperties.getFromName());
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(htmlContent, true);
            
            if (cc != null && cc.length > 0) {
                helper.setCc(cc);
            }
            
            mailSender.send(message);
            log.info("发送HTML邮件成功: senderId={}, to={}, subject={}", senderId, to, subject);
            
            // 记录发送频率
            if (senderId != null) {
                recordSendFrequency(senderId, to[0]);
            }
            return true;
        } catch (Exception e) {
            log.error("发送HTML邮件失败: senderId={}, to={}, subject={}, error={}", senderId, to, subject, e.getMessage());
            return false;
        }
    }
    
    /**
     * 发送 HTML 邮件（带抄送，同步，无频率限制）
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param cc 抄送列表
     * @return 是否成功
     */
    public boolean sendHtmlMail(String[] to, String subject, String htmlContent, String[] cc) {
        return sendHtmlMail(null, to, subject, htmlContent, cc);
    }
    
    /**
     * 发送带附件的邮件（同步）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendMailWithAttachmentAsync 异步方法
     *
     * @param to 收件人
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param attachments 附件列表（文件路径）
     * @return 是否成功
     */
    public boolean sendMailWithAttachment(String to, String subject, String htmlContent, List<String> attachments) {
        return sendMailWithAttachment(new String[]{to}, subject, htmlContent, attachments);
    }
    
    /**
     * 发送带附件的邮件（批量，同步）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendMailWithAttachmentAsync 异步方法
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param attachments 附件列表（文件路径）
     * @return 是否成功
     */
    public boolean sendMailWithAttachment(String[] to, String subject, String htmlContent, List<String> attachments) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, mailProperties.getDefaultEncoding());
            
            helper.setFrom(getFromAddress(), mailProperties.getFromName());
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(htmlContent, true);
            
            // 添加附件
            if (attachments != null && !attachments.isEmpty()) {
                for (String filePath : attachments) {
                    File file = new File(filePath);
                    if (file.exists()) {
                        helper.addAttachment(file.getName(), file);
                    } else {
                        log.warn("附件文件不存在: {}", filePath);
                    }
                }
            }
            
            mailSender.send(message);
            log.info("发送带附件邮件成功: to={}, subject={}, attachments={}", to, subject, attachments);
            return true;
        } catch (Exception e) {
            log.error("发送带附件邮件失败: to={}, subject={}, error={}", to, subject, e.getMessage());
            return false;
        }
    }
    
    /**
     * 发送模板邮件（同步，带频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendTemplateMailAsync 异步方法
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     * @return 是否成功
     */
    public boolean sendTemplateMail(String senderId, String to, String subject, String template, Map<String, String> params) {
        String content = replaceTemplate(template, params);
        return sendHtmlMail(senderId, to, subject, content);
    }
    
    /**
     * 发送模板邮件（同步，无频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendTemplateMailAsync 异步方法
     *
     * @param to 收件人
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     * @return 是否成功
     */
    public boolean sendTemplateMail(String to, String subject, String template, Map<String, String> params) {
        String content = replaceTemplate(template, params);
        return sendHtmlMail(null, to, subject, content);
    }
    
    /**
     * 发送模板邮件（批量，同步，带频率限制）
     * 注意：此方法会阻塞当前线程直到邮件发送完成
     * 建议使用 sendTemplateMailAsync 异步方法
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人列表
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     * @return 是否成功
     */
    public boolean sendTemplateMail(String senderId, String[] to, String subject, String template, Map<String, String> params) {
        String content = replaceTemplate(template, params);
        return sendHtmlMail(senderId, to, subject, content, null);
    }
    
    /**
     * 发送模板邮件（批量，同步，无频率限制）
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     * @return 是否成功
     */
    public boolean sendTemplateMail(String[] to, String subject, String template, Map<String, String> params) {
        String content = replaceTemplate(template, params);
        return sendHtmlMail(null, to, subject, content, null);
    }
    
    // ==================== 异步发送方法 ====================
    
    /**
     * 异步发送简单文本邮件
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    @Async
    public CompletableFuture<Boolean> sendSimpleMailAsync(String to, String subject, String content) {
        boolean result = sendSimpleMail(to, subject, content);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送简单文本邮件（批量）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param content 内容
     */
    @Async
    public CompletableFuture<Boolean> sendSimpleMailAsync(String[] to, String subject, String content) {
        boolean result = sendSimpleMail(to, subject, content);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送 HTML 邮件
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人
     * @param subject 主题
     * @param htmlContent HTML 内容
     */
    @Async
    public CompletableFuture<Boolean> sendHtmlMailAsync(String to, String subject, String htmlContent) {
        boolean result = sendHtmlMail(to, subject, htmlContent);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送 HTML 邮件（带抄送）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param cc 抄送列表
     */
    @Async
    public CompletableFuture<Boolean> sendHtmlMailAsync(String[] to, String subject, String htmlContent, String[] cc) {
        boolean result = sendHtmlMail(to, subject, htmlContent, cc);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送带附件的邮件
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param attachments 附件列表（文件路径）
     */
    @Async
    public CompletableFuture<Boolean> sendMailWithAttachmentAsync(String to, String subject, String htmlContent, List<String> attachments) {
        boolean result = sendMailWithAttachment(to, subject, htmlContent, attachments);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送带附件的邮件（批量）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param htmlContent HTML 内容
     * @param attachments 附件列表（文件路径）
     */
    @Async
    public CompletableFuture<Boolean> sendMailWithAttachmentAsync(String[] to, String subject, String htmlContent, List<String> attachments) {
        boolean result = sendMailWithAttachment(to, subject, htmlContent, attachments);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送模板邮件
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     */
    @Async
    public CompletableFuture<Boolean> sendTemplateMailAsync(String to, String subject, String template, Map<String, String> params) {
        boolean result = sendTemplateMail(to, subject, template, params);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送模板邮件（批量）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param to 收件人列表
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     */
    @Async
    public CompletableFuture<Boolean> sendTemplateMailAsync(String[] to, String subject, String template, Map<String, String> params) {
        boolean result = sendTemplateMail(to, subject, template, params);
        return CompletableFuture.completedFuture(result);
    }
    
    // ==================== 带发送人参数的异步方法 ====================
    
    /**
     * 异步发送简单文本邮件（带频率限制）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    @Async
    public CompletableFuture<Boolean> sendSimpleMailAsync(String senderId, String to, String subject, String content) {
        boolean result = sendSimpleMail(senderId, to, subject, content);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送 HTML 邮件（带频率限制）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人
     * @param subject 主题
     * @param htmlContent HTML 内容
     */
    @Async
    public CompletableFuture<Boolean> sendHtmlMailAsync(String senderId, String to, String subject, String htmlContent) {
        boolean result = sendHtmlMail(senderId, to, subject, htmlContent);
        return CompletableFuture.completedFuture(result);
    }
    
    /**
     * 异步发送模板邮件（带频率限制）
     * 此方法立即返回，不会阻塞当前线程
     *
     * @param senderId 发送人ID（用于频率限制）
     * @param to 收件人
     * @param subject 主题
     * @param template 模板内容（支持 ${变量名} 格式）
     * @param params 模板参数
     */
    @Async
    public CompletableFuture<Boolean> sendTemplateMailAsync(String senderId, String to, String subject, String template, Map<String, String> params) {
        boolean result = sendTemplateMail(senderId, to, subject, template, params);
        return CompletableFuture.completedFuture(result);
    }
    
    // ==================== 私有方法 ====================
    
    /**
     * 检查频率限制
     * 
     * @param senderId 发送人ID
     * @param to 收件人
     * @return true表示可以发送，false表示被限制
     */
    private boolean checkFrequencyLimit(String senderId, String to) {
        try {
            String key = buildFrequencyKey(senderId, to);
            Boolean exists = redisTemplate.hasKey(key);
            return exists == null || !exists;
        } catch (Exception e) {
            log.error("检查邮件发送频率失败: senderId={}, to={}, error={}", senderId, to, e.getMessage());
            // 出错时允许发送
            return true;
        }
    }
    
    /**
     * 记录发送频率
     * 
     * @param senderId 发送人ID
     * @param to 收件人
     */
    private void recordSendFrequency(String senderId, String to) {
        try {
            String key = buildFrequencyKey(senderId, to);
            redisTemplate.opsForValue().set(key, "1", FREQUENCY_LIMIT_SECONDS, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("记录邮件发送频率失败: senderId={}, to={}, error={}", senderId, to, e.getMessage());
        }
    }
    
    /**
     * 构建频率限制的 Redis Key
     * 
     * @param senderId 发送人ID
     * @param to 收件人
     * @return Redis Key
     */
    private String buildFrequencyKey(String senderId, String to) {
        return MAIL_FREQUENCY_KEY_PREFIX + senderId + ":" + to;
    }
    
    /**
     * 替换模板变量
     *
     * @param template 模板内容
     * @param params 参数 Map
     * @return 替换后的内容
     */
    private String replaceTemplate(String template, Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return template;
        }
        
        String result = template;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            result = result.replace("${" + entry.getKey() + "}", entry.getValue());
        }
        return result;
    }
    
    /**
     * 获取发件人地址
     */
    private String getFromAddress() {
        String from = mailProperties.getFrom();
        if (!StringUtils.hasText(from)) {
            from = mailProperties.getUsername();
        }
        return from;
    }
}
